package com.pine.app.module.security.core.exception;

import com.alibaba.fastjson.JSON;
import com.pine.app.module.security.core.common.AuthConstant;
import com.pine.app.module.security.core.common.Result;
import com.pine.app.module.security.core.common.enums.ResponseProduceType;
import com.pine.app.module.security.oauth.exception.AuthenticationException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author xiaoyuan
 * @create 2020/3/21 14:33
 **/
public abstract class AbstractExceptionEntryPoint implements ExceptionEntryPoint {
    private static final String JSON_TYPE = "application/json";
    private static final String X_TYPE = "XMLHttpRequest";


    protected <T extends BaseException> void responseObject(T e, HttpServletRequest httpServletRequest,
                                                            HttpServletResponse response) throws ServletException, IOException {
        String pagePath = e.getPagePath();
        ResponseProduceType responseProduceTypeEnum = e.getResponseProduceTypeEnum();
        int code = e.getErrorType().code();
        String message = e.getMessage();
        Object data = e.getData();
        Result result = Result.build(code, message, data, pagePath);
        // 指定返回类型
        if (null != responseProduceTypeEnum) {
            if (responseProduceTypeEnum == ResponseProduceType.JSON) {
                returnJson(handlerResponseCode(e),result, response);
                return;
            }
            if (responseProduceTypeEnum == ResponseProduceType.HTML) {
                returnHtml(httpServletRequest, response, message, pagePath);
                return;
            }
        }
        // 没有指定返回类型，根据 http 请求头进行判断返回什么类型
        String contentTypeHeader = httpServletRequest.getHeader("Content-Type");
        String acceptHeader = httpServletRequest.getHeader("Accept");
        String xRequestedWith = httpServletRequest.getHeader("X-Requested-With");
        boolean checkIsJson = (contentTypeHeader != null && contentTypeHeader.contains(JSON_TYPE)) || (acceptHeader != null && acceptHeader.contains(JSON_TYPE)) || X_TYPE.equalsIgnoreCase(xRequestedWith);
        if (checkIsJson) {
            returnJson(handlerResponseCode(e),result, response);
        } else {
            returnHtml(httpServletRequest, response, message, pagePath);
        }
    }

    protected void returnJson(Integer code, Result result, HttpServletResponse response) throws ServletException {

        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.setStatus(code);
        PrintWriter out = null;
        try {
            out = response.getWriter();
            out.append(JSON.toJSONString(result));
        } catch (Exception e) {
            throw new ServletException();
        } finally {
            IOUtils.closeQuietly(out);
        }
    }

    protected void returnHtml(HttpServletRequest request, HttpServletResponse response, String message, String pagePath) throws ServletException, IOException {
        if (StringUtils.isNotEmpty(message)) {
            request.setAttribute(AuthConstant.DEFAULT_LOGIN_ERROR_KEY, message);
        }
        if (StringUtils.isBlank(pagePath)) {
            pagePath = "error";
        }
        RequestDispatcher dispatcher = request.getRequestDispatcher(pagePath);
        dispatcher.forward(request, response);
    }


    private int handlerResponseCode(RuntimeException e){
        int code = 500;
        if(e instanceof AuthenticationException){
            code = 401;
        }
        if(e instanceof  AccessDeniedException){
            code = 403;
        }
        return code;
    }


}
